package org.outlook.xnotepad.action;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.text.JTextComponent;

import org.apache.commons.lang.StringUtils;
import org.outlook.xnotepad.pojo.Comman;

public class FindAction extends AbstractAction {

	private static final long serialVersionUID = 5951593734545420925L;
	
	JTextField findText=new JTextField("");
	JTextField replaceText=new JTextField("");
	JRadioButton up = new JRadioButton("向上(U)");
	JRadioButton down = new JRadioButton("向下(D)");
	JRadioButton all = new JRadioButton("All");
	JRadioButton selected = new JRadioButton("Selected");
	JCheckBox matchcase = new JCheckBox("区分大小写");
	JCheckBox regex = new JCheckBox("正则表达式");
	JCheckBox comman = new JCheckBox("扩展命令");
	JButton findBtn=new JButton("查找");
	JButton replaceBtn = new JButton("替换");
	JButton replaceAndFindBtn = new JButton("替换/查找");
	JButton replaceAllBtn=new JButton("替换全部");

	private Frame frame;
	private JLabel messager;
	private JTextComponent editor;

	private Dimension labelDimension = new Dimension(70,20);
	private Dimension textDimension = new Dimension(150,20);
	private Dimension btnDimension = new Dimension(80,20);

	private JDialog dialog;

	public FindAction() {
		super("Find");
	}

	public FindAction(Frame frame, JLabel toolbar, JTextComponent editor) {
		super("Find");
		this.frame = frame;
		this.messager=toolbar;
		this.editor=editor;
	}
//
//	public FindAction(Notepad notepad) {
//		super("Find");
//		this.frame = notepad.getFrame();
//		this.editor=notepad.getEditor();
//	}

	public void actionPerformed(ActionEvent e) {
		dialog = new JDialog(frame,"查找",false);
//		JDialog dialog = new JDialog();

		JPanel textPanel = new JPanel();
		JPanel centerPanel = new JPanel();
		JPanel optionPanel = new JPanel();
		JPanel bottomPanel = new JPanel();

		JLabel findLebel=new JLabel("查找内容");
		JLabel replaceLabel=new JLabel("替换内容");
		findLebel.setPreferredSize(labelDimension);
		replaceLabel.setPreferredSize(labelDimension);

		findText.setText("");
		findText.setSize(textDimension);
		textPanel.setLayout(new GridLayout(2,2));
		textPanel.add(findLebel);
		textPanel.add(findText);
		textPanel.add(replaceLabel);
		textPanel.add(replaceText);
		
		ButtonGroup directionGroup = new ButtonGroup();
		down.setSelected(true);
		directionGroup.add(up);
		directionGroup.add(down);

		ButtonGroup scopeGroup = new ButtonGroup();
		all.setSelected(true);
		scopeGroup.add(all);
		scopeGroup.add(selected);
		
		JPanel direction = new JPanel();
		direction.setBorder(BorderFactory.createTitledBorder("Direction"));
		direction.add(up);
		direction.add(down);
		direction.setPreferredSize(new Dimension(170, 60));

		JPanel scope = new JPanel();
		scope.setBorder(BorderFactory.createTitledBorder("Scope"));
		scope.add(all);
		scope.add(selected);
		scope.setPreferredSize(new Dimension(170, 60));
		
		centerPanel.add(direction);
		centerPanel.add(scope);

		optionPanel.setBorder(BorderFactory.createTitledBorder("Option"));
		optionPanel.add(matchcase);
		optionPanel.add(regex);
		optionPanel.add(comman);

		findBtn.setPreferredSize(btnDimension);
		replaceBtn.setPreferredSize(btnDimension);
		replaceAndFindBtn.setPreferredSize(btnDimension);
		replaceAllBtn.setPreferredSize(btnDimension);
		bottomPanel.setLayout(new GridLayout(2,2));
		bottomPanel.add(findBtn);
		bottomPanel.add(replaceBtn);
		bottomPanel.add(replaceAndFindBtn);
		bottomPanel.add(replaceAllBtn);
		
		attachActionListener();

		dialog.getContentPane().setLayout(new GridLayout(4,1));
		dialog.add(textPanel);
		dialog.add(centerPanel);
		dialog.add(optionPanel);
		dialog.add(bottomPanel);
		dialog.setSize(400, 300);
		dialog.setModal(true);
		dialog.setModalityType(ModalityType.MODELESS);
//		dialog.setLocationRelativeTo(this.frame);
		dialog.setVisible(true);
	}

	private Pattern pattern;
	private Matcher matcher;
	private String lastSearchText=null;
	private boolean contentUpdated=true;
	private void attachActionListener() {
		dialog.addWindowListener(new WindowListener() {

			@Override
			public void windowActivated(WindowEvent e) {
			}

			@Override
			public void windowClosed(WindowEvent e) {
			}

			@Override
			public void windowClosing(WindowEvent e) {
				pattern=null;
				matcher=null;
				lastSearchText=null;
				contentUpdated=true;
			}

			@Override
			public void windowDeactivated(WindowEvent e) {
			}

			@Override
			public void windowDeiconified(WindowEvent e) {
			}

			@Override
			public void windowIconified(WindowEvent e) {
			}

			@Override
			public void windowOpened(WindowEvent e) {
			}
			
		});
		
		findBtn.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				String searchText = findText.getText();
				String originalText = editor.getText();
				if(StringUtils.isNotBlank(searchText) && StringUtils.isNotBlank(originalText)) {
					int caretPosition = editor.getCaretPosition();

					if(!matchcase.isSelected() && !regex.isSelected()) {
						searchText = searchText.toLowerCase();
						originalText = originalText.toLowerCase();
					}

					int targetPosition=-1;
					if(regex.isSelected()) {
						searchText=MUTILINE+searchText;
						if(pattern == null || !searchText.equals(lastSearchText) || contentUpdated) {
							pattern = getPattern(searchText);
							matcher = pattern.matcher(originalText);
						}
						int matcherEnd=-1;
						if (up.isSelected()) {
							int rangeEnd=-1;
							if(editor.getSelectedText()!=null && editor.getSelectedText().matches(searchText))
								rangeEnd = editor.getSelectionStart()-1;
							else
								rangeEnd = caretPosition;
							int lastMatchPosition=-1;
							matcher = pattern.matcher(originalText);
							while(matcher.find() && lastMatchPosition<rangeEnd){
								if(matcher.start()>rangeEnd)
									break;
								lastMatchPosition=matcher.start();
								matcherEnd=matcher.end();
							}
							targetPosition = lastMatchPosition;
						} else {
							if(editor.getSelectedText()!=null && editor.getSelectedText().matches(searchText)) {
								if(matcher.find(editor.getSelectionEnd()+1)) {
									targetPosition = matcher.start();
									matcherEnd=matcher.end();
								}
							} else
								if(matcher.find(caretPosition)) {
									targetPosition = matcher.start();
									matcherEnd=matcher.end();
								}
						}

						if(targetPosition<0) {
							//no found
						} else {
							editor.select(targetPosition, matcherEnd);
							editor.setSelectedTextColor(Color.orange);
						}
					} else {
						if (up.isSelected()) {
							if(searchText.equalsIgnoreCase(editor.getSelectedText()))
								targetPosition = originalText.lastIndexOf(searchText, editor.getSelectionStart()-1);
							else
								targetPosition = originalText.lastIndexOf(searchText, caretPosition);
						} else {
							if(searchText.equalsIgnoreCase(editor.getSelectedText()))
								targetPosition = originalText.indexOf(searchText, editor.getSelectionEnd()+1);
							else
								targetPosition = originalText.indexOf(searchText, caretPosition);
						}
						
						if(targetPosition<0) {
							//no found
						} else {
							editor.select(targetPosition, targetPosition+searchText.length());
							editor.setSelectedTextColor(Color.orange);
						}
					}
					lastSearchText=searchText;
					contentUpdated=false;
				}
			}

		});
		
		replaceBtn.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				String searchText = findText.getText();
				if(StringUtils.isBlank(editor.getText()) || StringUtils.isBlank(searchText))
					return ;
				if(StringUtils.isBlank(replaceText.getText()))
					replaceText.setText("");
				if (replaceText.getText().length() > 0 && editor.getSelectedText() != null) {
					if(regex.isSelected() && editor.getSelectedText().matches(searchText)) {
						searchText=MUTILINE+searchText;
						int selectionStart = editor.getSelectionStart();
						editor.replaceSelection(replaceText.getText());
						editor.select(selectionStart, selectionStart+replaceText.getText().length());
						contentUpdated=true;
					}
					else if((!matchcase.isSelected() && editor.getSelectedText().equalsIgnoreCase(searchText)) || (matchcase.isSelected() && editor.getSelectedText().equals(searchText))) {
						int selectionStart = editor.getSelectionStart();
						editor.replaceSelection(replaceText.getText());
						editor.select(selectionStart, selectionStart+replaceText.getText().length());
						contentUpdated=true;
					}
				} else {
					findBtn.doClick();
				}
			}

		});

		replaceAndFindBtn.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				if(StringUtils.isBlank(replaceText.getText()) || StringUtils.isBlank(editor.getText()) || StringUtils.isBlank(findText.getText()))
					return ;
				if (replaceText.getText().length() > 0 && editor.getSelectedText() != null) {
					if(regex.isSelected() && editor.getSelectedText().matches(findText.getText())) {
						int selectionStart = editor.getSelectionStart();
						editor.replaceSelection(replaceText.getText());
						editor.select(selectionStart, selectionStart+replaceText.getText().length());
						contentUpdated=true;
						findBtn.doClick();
					}
					else if((!matchcase.isSelected() && editor.getSelectedText().equalsIgnoreCase(findText.getText())) || (matchcase.isSelected() && editor.getSelectedText().equals(findText.getText()))) {
						int selectionStart = editor.getSelectionStart();
						editor.replaceSelection(replaceText.getText());
						editor.select(selectionStart, selectionStart+replaceText.getText().length());
						contentUpdated=true;
						findBtn.doClick();
					}
				} else {
					findBtn.doClick();
				}
			}

		});
		replaceAllBtn.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				String searchText = findText.getText();
				String originalText = editor.getText();
				if(StringUtils.isNotBlank(searchText) && StringUtils.isNotBlank(originalText)) {
					int caretPosition = editor.getCaretPosition();

					if(!matchcase.isSelected() && !regex.isSelected()) {
						searchText = searchText.toLowerCase();
						originalText = originalText.toLowerCase();
					}

					if(regex.isSelected()) {
						searchText=MUTILINE+searchText;
						int startPosition, endPosition;
						if (up.isSelected()) {
							startPosition=0;
							endPosition=caretPosition;
						} else {
							startPosition=caretPosition;
							endPosition=originalText.length();
						}
						String subStr = originalText.substring(startPosition, endPosition);
						if(comman.isSelected()) {
							try {
								Comman comman = new Comman(replaceText.getText());
								StringBuffer sb = new StringBuffer();
								Pattern pattern = Pattern.compile(searchText);
								Matcher matcher = pattern.matcher(subStr);
								int index=1;
								while(matcher.find()) {
									if(startPosition>endPosition)
										break;
									matcher.appendReplacement(sb, comman.getResult(index++));
								}
								matcher.appendTail(sb);
								editor.setText(originalText.replace(subStr, sb));
							} catch (Exception ee) {
								ee.printStackTrace();
							}
						} else {
							if (up.isSelected())
								editor.setText(subStr.replaceAll(searchText, replaceText.getText())+originalText.substring(caretPosition));
							else
								editor.setText(originalText.substring(0,caretPosition)+subStr.replaceAll(searchText, replaceText.getText()));
						}
					} else {
						StringBuffer sb = new StringBuffer(editor.getText());
						int startPosition, endPosition;
						if (up.isSelected()) {
							startPosition=0;
							if(searchText.equalsIgnoreCase(editor.getSelectedText()))
								endPosition=editor.getSelectionStart();
							else
								endPosition=originalText.length()-1;
						} else {
							endPosition=originalText.length()-1;
							if(searchText.equalsIgnoreCase(editor.getSelectedText()))
								startPosition=caretPosition;
							else
								startPosition=0;
						}
						int numOfChange=0;
						while(startPosition>-1 && startPosition<endPosition) {
							startPosition=originalText.indexOf(searchText, startPosition);
							if(startPosition==-1)
								break;
							sb.replace(startPosition, startPosition=startPosition+searchText.length(), replaceText.getText());
							numOfChange++;
						}
						if(numOfChange>0){
							editor.setText(sb.toString());
							//message
						}
						sb=null;
						//TODO change color
					}
					lastSearchText=searchText;
					contentUpdated=false;
				}
			}

		});
	}
	private final static String MUTILINE="(?m)";

	protected Pattern getPattern(String searchText) {
		if(null==pattern)
			pattern=Pattern.compile(searchText,Pattern.MULTILINE);
		return pattern;
	}

}